package br.ufsc.ctc.ine5622.compilador.semantico;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.NoSuchElementException;

import br.ufsc.ctc.ine5622.compilador.lex.Semantico;
import br.ufsc.ctc.ine5622.compilador.lex.Semantico.Categoria;

/**
 * Classe que representa a linha da tabela de simbolos.
 * Cada coluna é representada pelos atributos da classe: nome, categoria e posição (estas colunas todas as linhas preenchem).
 * As colunas que são preenchidas por apenas algumas linhas estão representadas na hashtable colunas, cuja chave representa 
 * o nome da coluna, e o objeto contido, o seu valor.
 * A chave da hash é o enumerado ColunaKey, cada tipo representa uma coluna. O tipo do valor guardado na coluna é marcado 
 * em cada objeto enumerado.
 * @author paulo
 * @author william
 *
 */
public class Simbolo {
	
	public enum ColunaKey{
		VALUE                   (Object.class),                  // Valor de constantes
		NIVEL                   (Integer.class),                 // Nivel léxico de escopo
		TIPO                    (Semantico.TipoVariavel.class),  // Tipo do simbolo, variavel, constante, função, vetor, etc
		TIPO_ELEMENTOS			(Semantico.TipoVariavel.class),  // Tipo dos elementos do vetor ou arranjo
		NUM_PAR_FORMAIS         (Integer.class),                 // Número de parametros em funções e procedimentos
		LISTA_PAR_FORMAIS       (Object.class),                  // Lista de parametros
		TIPO_RETORNO            (Integer.class),                 // Tipo do retorno da função
		MP_PAR                  (Semantico.MpPar.class),         // Método de passagem de parametro, por valor ou por referência
		TAMANHO_CADEIA			(Integer.class),                 // Tamanho da cadeia
		LIMITE_1_DIM_1          (Integer.class),                 // Limite inferior da primeira dimensão de vetor
		LIMITE_2_DIM_1          (Integer.class),                 // Limite superior da primeira dimensão de vetor
		LIMITE_1_DIM_2          (Integer.class),                 // Limite inferior da segunda dimensão de vetor
		LIMITE_2_DIM_2          (Integer.class),                 // Limite superior da segunda dimensão de vetor
		NUMERO_DIMENSOES        (Integer.class);                 // Número de dimensões que o vetor tem
		
		
		public Class tipoDoValor = null;
		
		ColunaKey(Class tipo){
			tipoDoValor = tipo;
		}
		
	}
	
	private String nome;
	private Categoria categoria;
	private int posicao;
	private Hashtable<ColunaKey, Object> colunas = new Hashtable<ColunaKey, Object>();

	public Simbolo(String n, Categoria cat, int pos) {
		nome = n;
		categoria = cat;
		posicao = pos;
	}
	
	public int getPosicao() {
		return posicao;
	}

	public void setPosicao(int posicao) {
		this.posicao = posicao;
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public Categoria getCategoria() {
		return categoria;
	}

	public void setCategoria(Categoria categoria) {
		this.categoria = categoria;
	}

	public Hashtable<ColunaKey, Object> getColunas() {
		return colunas;
	}
	
	public void adicionaColuna(ColunaKey colunaNome, Object valor){
		colunas.put(colunaNome, valor);
	}
	
	public Object getvalue(){
		return (Object)colunas.get(ColunaKey.VALUE);
	}
	public int getNivel(){
		return (Integer)colunas.get(ColunaKey.NIVEL);
	}
	public Semantico.TipoVariavel getTipo(){
		return (Semantico.TipoVariavel)colunas.get(ColunaKey.TIPO);
	}
	public Semantico.TipoVariavel getTipoElementos(){
		return (Semantico.TipoVariavel)colunas.get(ColunaKey.TIPO_ELEMENTOS);
	}
	@SuppressWarnings("unchecked")
	public List<Simbolo> getListaParFormais(){
		return (List<Simbolo>)colunas.get(ColunaKey.LISTA_PAR_FORMAIS);
	}
	public Semantico.TipoVariavel getTipoRetorno(){
		return (Semantico.TipoVariavel)colunas.get(ColunaKey.TIPO_RETORNO);
	}
	public Semantico.MpPar getMpPar(){
		return (Semantico.MpPar)colunas.get(ColunaKey.MP_PAR);
	}
	public int getTamanhoCadeia(){
		return (Integer)colunas.get(ColunaKey.TAMANHO_CADEIA);
	}
	public int getLimite1Dim1(){
		return (Integer)colunas.get(ColunaKey.LIMITE_1_DIM_1);
	}
	public int getLimite2Dim1(){
		return (Integer)colunas.get(ColunaKey.LIMITE_2_DIM_1);
	}
	public int getLimite2Dim2(){
		return (Integer)colunas.get(ColunaKey.LIMITE_2_DIM_2);
	}
	public int getLimite1Dim2(){
		return (Integer)colunas.get(ColunaKey.LIMITE_1_DIM_2);
	}
	public int getNumeroDimensoes(){
		return (Integer)colunas.get(ColunaKey.NUMERO_DIMENSOES);
	}
	public int getNumeroParFormais(){
		return (Integer)colunas.get(ColunaKey.NUM_PAR_FORMAIS);
	}

	public String toString () {
		String out = "Nome: " +nome+ "\ncategoria: " +categoria+ "\nposicao: " +posicao;
        Enumeration<ColunaKey> en = colunas.keys();
        while (en.hasMoreElements ()) {
            ColunaKey key = (ColunaKey) en.nextElement ();
            Object value = (Object) colunas.get (key);
            out += "\n " + key + ": " + value;
        }
        return out;
    } 

}
